<script lang="ts" setup>

import {StyleValue, computed, ref, watch, useSlots, provide} from "vue";
import {TreeSelectSize} from "@layui/layui-vue/types/component/treeSelect/interface";
import {ReplaceFieldsOptionsOptional, SearchNodeMethodType} from "@layui/layui-vue/types/component/tree/tree.type";
import {DropdownTeleportProps} from "@layui/layui-vue/types/component/dropdown/interface";
import {VirtTree} from "@/components/VirtTree";
import {TreeFieldNames} from "vue-virt-list";
import {findNode, getChildren, traverseTree} from "@/utils/tree";
// import { getNode } from "../../utils";
// import { fillFieldNames } from "../tree/utils";
// import {
//   ReplaceFieldsOptionsOptional,
//   LoadFunction,
//   SearchNodeMethodType,
// } from "../tree/tree.type";
// import { LAYUI_TREE_SELECT } from "./useTreeSelect";

export interface TreeSelectProps {
  modelValue: any;
  data: any;
  size?: TreeSelectSize;
  multiple?: boolean;
  allowClear?: boolean;
  disabled?: boolean;
  placeholder?: string;
  checkStrictly?: boolean;
  collapseTagsTooltip?: boolean;
  minCollapsedNum?: number;
  search?: boolean;
  searchNodeMethod?: SearchNodeMethodType;
  contentClass?: string | Array<string | object> | object;
  contentStyle?: StyleValue;
  replaceFields?: TreeFieldNames;
  defaultExpandAll?: boolean;
  teleportProps?: DropdownTeleportProps;
}

export interface TreeSelectEmits {
  (e: "update:modelValue", value: string | string[]): void;

  (e: "change", value: string | string[]): void;

  (e: "search", value: string | string[]): void;
}

defineOptions({
  name: "LayTreeSelect",
});
const emits = defineEmits<TreeSelectEmits>();
const props = withDefaults(defineProps<TreeSelectProps>(), {
  disabled: false,
  multiple: false,
  allowClear: false,
  checkStrictly: true,
  collapseTagsTooltip: true,
  minCollapsedNum: 1,
  search: false,
  searchNodeMethod: (node: any, value: string) => {
    return node.title.includes(value);
  },
  defaultExpandAll: false,
});


// const {size} = useProps(props);
const openState = ref(false);
const searchValue = ref();
const multipleValue = ref([]);
const dropdownRef = ref();
const singleValue = ref("");
const composing = ref(false);
const treeRef = ref();
const checkedKeys = computed({
  get() {
    return props.multiple ? props.modelValue : [];
  },
  set(value) {
    if (props.multiple) {
      emits("update:modelValue", value);
      emits("change", value);
    }
  },
});
const selectedValue = computed({
  get() {
    if (Array.isArray(props.modelValue)) {
      return props.modelValue;
    } else if (props.modelValue) {
      return [props.modelValue]
    }
    return []
  },
  set(value) {
    if (props.modelValue !== value) {
      const data = props.multiple ? value : value[0];
      emits("update:modelValue", data);
      emits("change", data);
    }
  },
});
/**
 * 实时标识，是否存在数据
 *
 * 应用于多选模式 placeholder 属性的显示隐藏
 */
const hasContent = computed(() => {
  if (props.multiple) {
    console.log(checkedKeys.value)
    return checkedKeys.value.length > 0;
  } else {
    return selectedValue.value.length
  }
});

const _placeholder = computed(() => {
  return hasContent.value ? "" : props.placeholder;
});
const fillFieldNames = (
    replaceFields?: TreeFieldNames
): TreeFieldNames => {
  const {key, title, children} = replaceFields || {};

  return {
    key: key || "id",
    title: title || "title",
    children: children || "children",
  };
};
const _replaceFields: any = computed(() => fillFieldNames(props.replaceFields));


/**
 * Tag 标签的删除事件
 *
 * 备注: 多选模式需要考虑 checkStrictly 为 false 的情况，删除当前节点，是否需要删除子节点, 如果为 true 时，仅删除当前节点
 */
const handleRemove = (value: any) => {
  // // 关闭 dropdown 前置操作
  // dropdownRef.value.hide();
  //
  // // 删除 checkedKeys 的逻辑
  // if (props.checkStrictly) {
  //   emits(
  //       "update:modelValue",
  //       checkedKeys.value.filter((item: any) => item != value)
  //   );
  // } else {
  //   // 当 checkStrictly 配置为 false 时, 删除内容为 当前节点 与 关联子集
  //   const node = getNode(props.data, value, _replaceFields.value);
  //   const nodeIds = filterNodeIds(node);
  //   emits(
  //       "update:modelValue",
  //       checkedKeys.value.filter((item: any) => !nodeIds.includes(item))
  //   );
  // }
};
const onClear = function () {
  selectedValue.value = [];
};


const onCompositionstart = () => {
  composing.value = true;
};

const onCompositionend = (eventParam: Event) => {
  composing.value = false;
  onSearch((eventParam.target as HTMLInputElement).value);
};
const onSearch = (value: string) => {
  if (composing.value) return;
  emits("search", value);
  searchValue.value = value;
};
/**
 * Tree 节点单击事件
 *
 * 备注：单选模式需要执行的逻辑，多选模式禁用。
 *
 * @param node 当前节点
 */
const handleSelect = (node: any[]) => {
  // singleValue.value = node[_replaceFields.value.title];
  dropdownRef.value.hide();
};


watch(openState, () => {
  if (!openState.value) {
    searchValue.value = "";
  }
});

watch(
    [selectedValue, checkedKeys, props.data],
    () => {
      const {key, title} = _replaceFields.value;
      if (props.multiple) {
        try {
          multipleValue.value = checkedKeys.value.map((value: any) => {
            let node: any = findNode(
                props.data,
                (node: any) => {
                  if (node[key] == value) {

                    return node;
                  }
                },
                _replaceFields.value.children
            );

            if (node) {
              node.label = node[title];
              node.value = node[key];
              node.closable = !node.disabled;
            }

            if (node == undefined) {
              node = {
                label: value,
                value: value,
                closable: true,
              };
            }
            return node;
          });
        } catch (e) {
          throw new Error("v-model / model-value is not an array type");
        }
      } else {
        /**
         * 根据 id 查找 node 节点
         *
         * 备注：如果找不到这个节点, 说明存在 BUG 或 空值, 对 singleValue 清空
         */
        const node = findNode(props.data, (node: any) => {
          if (node[key] == selectedValue.value[0]) {

            return node;
          }
        }, _replaceFields.value.children)
        if (node) {
          singleValue.value = node[title];
        } else {
          singleValue.value = "";
        }
      }
    },
    {immediate: true, deep: true}
);
</script>

<template>
  <div
      class="layui-tree-select"
      :class="{
      'layui-disabled': disabled,
      'has-content': hasContent,
      'has-clear': allowClear,
    }"
  >
    <lay-dropdown
        ref="dropdownRef"
        :disabled="disabled"
        :contentClass="contentClass"
        :contentStyle="contentStyle"
        :teleportProps="teleportProps"
        :click-to-close="false"
        @show="openState = true"
        @hide="openState = false"
    >
      <lay-tag-input
          v-if="multiple"
          v-model="multipleValue"
          :size="size"
          :allow-clear="allowClear"
          :placeholder="_placeholder"
          :collapseTagsTooltip="collapseTagsTooltip"
          :minCollapsedNum="minCollapsedNum"
          :disabledInput="!search"
          :inputValue="searchValue"
          @input-value-change="onSearch"
          @remove="handleRemove"
          @clear="onClear"
          @keyup.delete.capture.prevent.stop
          @keydown.enter.capture.prevent.stop
      >
        <template #suffix>
          <lay-icon
              type="layui-icon-triangle-d"
              :class="{ triangle: openState }"
          ></lay-icon>
        </template>
      </lay-tag-input>
      <lay-input
          v-else
          :modelValue="singleValue"
          :allow-clear="allowClear"
          :placeholder="_placeholder"
          :disabled="disabled"
          :readonly="!search"
          :size="size"
          @clear="onClear"
          @input="onSearch"
          @compositionstart="onCompositionstart"
          @compositionend="onCompositionend"
      >
        <template #suffix>
          <lay-icon
              type="layui-icon-triangle-d"
              :class="{ triangle: openState }"
          ></lay-icon>
        </template>
      </lay-input>
      <template #content>
        <div class="layui-tree-select-content">
          <virt-tree ref="treeRef" :field-names="_replaceFields" :selectable="!multiple"
                     v-model:selected-keys="selectedValue"
                     v-model:checkedKeys="checkedKeys"
                     :checkable="multiple" :checked-strictly="checkStrictly" @select="handleSelect" show-line
                     :list="props.data">

            <template #content="{ node }">
              <slot name="title" :data="node">
                {{ node.title }}
              </slot>
            </template>
          </virt-tree>


        </div>
      </template>
    </lay-dropdown>
  </div>
</template>
